﻿using CTP.CRM.Core.OTel;
using CTP.CRM.Core.OTel.Options;
using CTP.CRM.Core.SqlSugar.Entitys;
using CTP.CRM.Core.SqlSugar.Options;
using SqlSugar;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;

namespace CTP.CRM.Core.SqlSugar
{
    //
    // 摘要:
    //     解决线程安全问题，基类必须是全局单例，不能放到泛型仓储里，不然每个泛型都是一个独立的实例
    public class SqlsugarScopeBasic
    {
        private static IServiceCollection _services;

        private static ConcurrentDictionary<string, SqlSugarScope> _cache = new ConcurrentDictionary<string, SqlSugarScope>();

        public static ISqlSugarClient GetContextSafely(string key)
        {
            return _cache[key];
        }

        internal static void Init(List<SqlsugarOptions> sqlsugarOptions, Action<object, DataFilterModel> onExecuting, IServiceCollection services, params string[] assemblyNames)
        {
            List<SqlsugarOptions> sqlsugarOptions2 = sqlsugarOptions;
            Action<object, DataFilterModel> onExecuting2 = onExecuting;
            _services = services;
            if ((from m in sqlsugarOptions2
                 group m by m.ConfigId).Any((IGrouping<string, SqlsugarOptions> m) => m.Count() > 1))
            {
                throw new Exception("ConfigId数据库唯一标识重复");
            }

            List<TableFilterItem<object>> filters = new List<TableFilterItem<object>>();
            foreach (string assemblyString in assemblyNames)
            {
                foreach (Type item2 in from t in Assembly.Load(assemblyString).GetTypes()
                                       where typeof(ISoftDeleteBasicEntity).IsAssignableFrom(t) && !t.IsAbstract
                                       select t)
                {
                    if (item2.GetProperty("IsDeleted") != null)
                    {
                        LambdaExpression expression = DynamicExpressionParser.ParseLambda(new ParameterExpression[1] { Expression.Parameter(item2, "it") }, typeof(bool), "IsDeleted == null || IsDeleted ==  @0", false);
                        filters.Add(new TableFilterItem<object>(item2, expression));
                    }
                }
            }

            List<ConnectionConfig> list = sqlsugarOptions2.Select((SqlsugarOptions m) => new ConnectionConfig
            {
                ConnectionString = m.ConnectionString,
                DbType = m.DbType,
                IsAutoCloseConnection = m.IsAutoCloseConnection,
                ConfigId = m.ConfigId
            }).ToList();
            foreach (ConnectionConfig item in list)
            {
                SqlSugarScope value = new SqlSugarScope(item, delegate (SqlSugarClient db)
                {
                    string connectId = item.ConfigId.ToString() ?? "default";
                    OTelOptions oTelOptions = ActivityHelper.OTelOptions;
                    if (oTelOptions != null && oTelOptions.EnableSql)
                    {
                        db.GetConnectionScope(connectId).Aop.OnLogExecuting = delegate (string sql, SugarParameter[] pars)
                        {
                            string sqlString = UtilMethods.GetSqlString(item.DbType, sql, pars);
                            if (sqlsugarOptions2.First((SqlsugarOptions m) => m.ConfigId == connectId).OpenSqlLog)
                            {
                                LogHelper.Debug($"\r\n    |-连接编号：{connectId}\r\n    |-执行时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss ffff}\r\n    |-执行Sql： \r\n        {sqlString}", false);
                            }

                            Activity activity2 = (SqlSugarActivityStorage.CurrentActivity = ActivityHelper.CreateSpanActivity("SqlSugar执行SQL"));
                            UtilMethods.GetNativeSql(sql, pars);
                            activity2.SetTag("db.type", item.DbType.ToString());
                            activity2.SetTag("db.instance", connectId);
                            OTelOptions oTelOptions2 = ActivityHelper.OTelOptions;
                            activity2.AddTag("db.sql", (oTelOptions2 != null && oTelOptions2.EnableSqlParameters) ? sqlString : sql);
                            activity2.Start();
                        };
                        db.GetConnectionScope(connectId).Aop.OnLogExecuted = delegate
                        {
                            Activity currentActivity2 = SqlSugarActivityStorage.CurrentActivity;
                            currentActivity2?.SetTag("db.execution_time", db.Ado.SqlExecutionTime);
                            currentActivity2?.Stop();
                            currentActivity2?.Dispose();
                            SqlSugarActivityStorage.CurrentActivity = null;
                        };
                        db.GetConnectionScope(connectId).Aop.OnError = delegate (SqlSugarException exp)
                        {
                            Activity currentActivity = SqlSugarActivityStorage.CurrentActivity;
                            currentActivity?.SetStatus(ActivityStatusCode.Error);
                            currentActivity?.SetTag("db.execution_error", true);
                            currentActivity?.SetTag("db.execution_error.message", exp.Message);
                            currentActivity?.Stop();
                            currentActivity?.Dispose();
                            SqlSugarActivityStorage.CurrentActivity = null;
                        };
                    }
                    else if (sqlsugarOptions2.First((SqlsugarOptions m) => m.ConfigId == connectId).OpenSqlLog)
                    {
                        db.GetConnectionScope(connectId).Aop.OnLogExecuting = delegate (string sql, SugarParameter[] pars)
                        {
                            LogHelper.Debug($"\r\n    |-连接编号：{connectId}\r\n    |-执行时间：{DateTime.Now:yyyy-MM-dd HH:mm:ss ffff}\r\n    |-执行Sql： \r\n        {UtilMethods.GetSqlString(item.DbType, sql, pars)}", false);
                        };
                    }

                    db.GetConnectionScope(connectId).Aop.DataExecuting = onExecuting2;
                    foreach (TableFilterItem<object> item3 in filters)
                    {
                        db.GetConnectionScope(connectId).QueryFilter.Add(item3);
                    }

                    db.Ado.IsDisableMasterSlaveSeparation = true;
                });
                _cache.TryAdd(item.ConfigId?.ToString(), value);
            }
        }
    }
}
